# _*_ coding:utf-8 _*_
import os
import re
from string import Template

from Logs.log_handle import get_log
from tools.allure_step import allure_step
from tools.db_model_tool import config_path
from tools.request_utils.cases_global_variables import GLOBAL_VARS
from tools.yaml_handle import ReadYaml

log = get_log(os.path.split(__file__)[-1])


def pre_expr_handle(content) -> object:
    """
    处理表达式替换，将模板字符串中的变量替换为全局变量值。

    :param content: 原始字符串内容
    :return: 替换后的字符串
    """
    if content is None:
        return None

    if len(content) != 0:
        log.info(f"开始进行字符串替换: 替换字符串为：{content}")
        content = Template(str(content)).safe_substitute(GLOBAL_VARS)
        for func in re.findall(r'\${(.*?)}', content):
            try:
                content = content.replace(f'${{{func}}}', exec_func(func))
            except Exception as e:
                log.exception(e)
        log.info(f"字符串替换完成: 替换字符串后为：{content}")

        return content


def str_to_python(content) -> object:
    """
    将字符串内容转换为 Python 对象，如将 "[1,2,3]" 转换为 [1,2,3]。

    :param content: 要转换的字符串内容
    :return: 转换后的 Python 对象a
    """
    if content is None:
        return None

    if isinstance(content, str) and len(content) > 0:
        return eval(content)
    else:
        return content


def exec_func(func: str) -> str:
    """
    执行函数并返回结果。

    :param func: 字符串形式的函数调用
    :return: 函数执行结果字符串
    """
    try:
        result = eval(func)
        return str(result)
    except Exception as e:
        log.exception(f"函数执行失败，函数：{func}，错误信息：{str(e)}")
        return ""


class RequestPreDataHandle:
    def __init__(self, request_data):
        self.request_data = request_data
        self.host: dict = ReadYaml(config_path).read_yaml
        self.whitelist = self.host.get("whitelist", [])  # 从配置中读取白名单 URL

    def _url_handle(self):
        """
        处理请求 URL，支持根据白名单判断是否需要拼接主机地址。
        """
        url = str(pre_expr_handle(self.request_data.get("url", "")))
        log.info(f"处理请求前 URL：{url}")
        if url in self.whitelist:
            self.request_data["url"] = url
        else:
            host = self.host["host"]
            if url.lower().startswith("http"):
                self.request_data["url"] = url
            else:
                self.request_data["url"] = f"{host.rstrip('/')}/{url.lstrip('/')}"
        allure_step('请求地址', self.request_data["url"])
        log.info(f"处理请求后 URL：{self.request_data['url']}")

    def _header_handle(self):
        """处理请求头，支持表达式替换和 Python 字符串转换。"""
        allure_step('请求头', self.request_data.get("header", None))
        if self.request_data.get("header", None):
            log.info(f"处理请求前头：{self.request_data.get('header')}")
            self.request_data["header"] = str_to_python(pre_expr_handle(self.request_data.get("header")))
            log.info(f"处理请求后头：{self.request_data['header']}")

    def _data_handle(self):
        """处理请求数据，支持表达式替换和 Python 字符串转换。"""
        allure_step('请求数据', self.request_data.get("data", None))
        if self.request_data.get("data", None):
            log.info(f"处理请求前 Data：{self.request_data.get('data')}")
            self.request_data["data"] = str_to_python(pre_expr_handle(self.request_data.get("data")))
            log.info(f"处理请求后 Data：{self.request_data['data']}")

    def _file_handle(self):
        """
        处理文件上传参数，支持单文件和多文件上传。
        """
        files = self.request_data.get("file", None)
        allure_step('请求文件', files)
        log.info(f"处理请求前文件：{files}")

        if files is None:
            return

        if isinstance(files, dict):
            processed_files = {}
            for key, value in files.items():
                if isinstance(value, list):
                    # 处理多文件上传
                    processed_files[key] = [(open(path, 'rb')) for path in value]
                else:
                    # 处理单文件上传
                    processed_files[key] = open(value, 'rb')
            self.request_data["file"] = processed_files
        else:
            log.error(f"文件参数格式不正确：{files}")

        log.info(f"处理请求后文件：{self.request_data['file']}")

    @property
    def to_request_data(self) -> dict:
        """
        处理请求数据，返回经过处理的请求数据字典。

        :return: 处理后的请求数据字典
        """
        self._url_handle()
        self._header_handle()
        self._data_handle()
        self._file_handle()
        return self.request_data
